﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CommandLineParser.cs" company="Matthias Friedrich">
//   Copyright © Matthias Friedrich 2013
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace CommandlineHandling
{
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    public class CommandLineParser
    {
        private const string CommandLinePattern = @"(?<q>[\/|-])(?<Name>\w+)[:]?(?<Value>[\w+\\\\\/\$\.:;\+\-\*\s\!\?\&\(\)]*)?";

        private readonly CommandLineHandler handler;

        public CommandLineParser(CommandLineHandler handler)
        {
            ExceptionExtensions.ThrowArgumentNullException(handler, () => handler);

            this.handler = handler;
        }

        public virtual IEnumerable<ICommandLineOption> Parse(IEnumerable<string> args)
        {
            ExceptionExtensions.ThrowArgumentNullException(args, () => args);

            ICommandLineOption current = null;

            var arguments = new List<ICommandLineOption>();

            foreach (string arg in args)
            {
                Match m = System.Text.RegularExpressions.Regex.Match(arg, CommandLinePattern);
                if (m.Success)
                {
                    string q = m.Groups["q"].Value;
                    string name = m.Groups["Name"].Value;
                    string v = m.Groups["Value"].Value.Trim();

                    if ("/".Equals(q))
                    {
                        ICommandLineOption nextArgument = this.CreateOption(name);

                        if (nextArgument != null)
                        {
                            nextArgument.Name = name;
                            nextArgument.Value = v;

                            arguments.Add(nextArgument);

                            if (current != null)
                            {
                                current.Next = nextArgument;
                            }

                            current = nextArgument;
                        }
                    }

                    if ("-".Equals(q) && (current != null))
                    {
                        current.Parameters.Add(new OptionParameter() { Name = name, Value = v });
                    }
                }
            }

            return arguments.AsReadOnly();
        }

        protected virtual ICommandLineOption CreateOption(string name)
        {
            ICommandLineOption instance = this.handler.Resolve(name);
            if (instance != null)
            {
                return instance;
            }

            Type t = this.handler.ResolveType(name);
            if ((t != null) && CommandLineHandler.IsOptionType(t))
            {
                return (ICommandLineOption)Activator.CreateInstance(t);
            }

            throw new InvalidOperationException();
        }
    }
}